
#ifndef _MEMBER_BSONNODE_H_
#define _MEMBER_BSONNODE_H_

#include <BMap>
#include <BSonNode>
#include <BSonDocument>

#define son_member(node)	((member_BSonNode*)((BSonNode*)node)->_ptr)

namespace BWE
{
	class SonFilter
	{
	public:
		SonFilter(const BString& desc);

		bool operator()(BSonNode* node) const;

		void addInfo(const BString& text);

		BString					name;
		BMap<BString, BString>	attribMap;
		BArray<BString>			includeTexts;
		BArray<BString>			excludeTexts;
	};
	class SonFormat
	{
	public:
		inline SonFormat()
		{
			head_prev = 0;
			head_post = 0;
			equal_prev = 0;
			equal_post = 0;
			semic_post = 0;
			tail_prev = 0;
			tail_post = 0;
		}

		inline void fromString(const BString& text)
		{
			this->text = text;
			head_prev = 0;
			head_post = 0;
			equal_prev = 0;
			equal_post = 0;
			semic_post = 0;
			tail_prev = 0;
			tail_post = 0;

			int head_pos = text.find('{');
			if (head_pos < text.size())
			{
				head_prev = text(head_pos - 1);
				head_post = text(head_pos + 1);
			}

			int tail_pos = text.find('}');
			if (tail_pos < text.size())
			{
				tail_prev = text(tail_pos - 1);
				tail_post = text(tail_pos + 1);
			}

			int equal_pos = text.find('=');
			if (equal_pos < text.size())
			{
				equal_prev = text(equal_pos - 1);
				equal_post = text(equal_pos + 1);
			}

			int semic_pos = text.find(';');
			if (semic_pos < text.size())
			{
				semic_post = text(semic_pos + 1);
			}

			if (head_prev && !isspace(head_prev))
				head_prev = 0;
			if (head_post && !isspace(head_post))
				head_post = 0;
			if (tail_prev && !isspace(tail_prev))
				tail_prev = 0;
			if (tail_post && !isspace(tail_post))
				tail_post = 0;
			if (equal_prev && !isspace(equal_prev))
				equal_prev = 0;
			if (equal_post && !isspace(equal_post))
				equal_post = 0;
			if (semic_post && !isspace(semic_post))
				semic_post = 0;
		}
		inline const BString& toString()
		{
			text.clear();
			if (head_prev || head_post)
			{
				text << head_prev << '{' << head_post;
			}
			if (tail_prev || tail_post)
			{
				text << tail_prev << '}' << tail_post;
			}
			if (equal_prev || equal_post)
			{
				text << equal_prev << '=' << equal_post;
			}
			if (semic_post)
			{
				text << ';' << semic_post;
			}
			return text;
		}

		inline void clear()
		{
			text.clear();
			head_prev = 0;
			head_post = 0;
			equal_prev = 0;
			equal_post = 0;
			semic_post = 0;
			tail_prev = 0;
			tail_post = 0;
		}

		BString		text;
		char		head_prev;
		char		head_post;
		char		equal_prev;
		char		equal_post;
		char		semic_post;
		char		tail_prev;
		char		tail_post;
	};
	class member_BSonNode
	{
	public:
		member_BSonNode(BSonNode* sonNode);
		~member_BSonNode();

		inline void raiseSignal(int signal, const BValue& value = BValue())
		{
			BSonNode* node = boss;
			while (node)
			{
				node->emit(signal, value);
				node = son_member(node)->parent;
			}
		}

		BSonNode* find(SonFilter& filter);

		BSonNode*				boss;
		BSonNode*				parent;
		BSonDocument*			document;
		BString					text;
		BMap<BString, BString>	attribMap;
		SonFormat				format;
		BArray<BSonNodeHolder>	children;

		bool					textDirty;
		BString					plainText;
	};
}

#endif
